# pragma once

# include "cpp_tools.h"
# include "serialib.h"

namespace WTRTK_982_4G
{
    const uint32_t crc_table[256] = {
        0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
        0x706af48fUL,
        0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL,
        0x97d2d988UL,
        0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL,
        0x6ab020f2UL,
        0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL,
        0x83d385c7UL,
        0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL,
        0x63066cd9UL,
        0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
        0xa2677172UL,
        0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL,
        0x42b2986cUL,
        0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL,
        0xabd13d59UL,
        0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL,
        0x56b3c423UL,
        0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL,
        0xb10be924UL,
        0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
        0x01db7106UL,
        0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL,
        0xe8b8d433UL,
        0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL,
        0x086d3d2dUL,
        0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL,
        0xf262004eUL,
        0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL,
        0x12b7e950UL,
        0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
        0xfbd44c65UL,
        0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL,
        0x3dd895d7UL,
        0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL,
        0xda60b8d0UL,
        0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL,
        0x270241aaUL,
        0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL,
        0xce61e49fUL,
        0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
        0x2eb40d81UL,
        0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL,
        0x74b1d29aUL,
        0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL,
        0x94643b84UL,
        0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL,
        0x7d079eb1UL,
        0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL,
        0x806567cbUL,
        0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
        0x67dd4accUL,
        0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL,
        0xa1d1937eUL,
        0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL,
        0x48b2364bUL,
        0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL,
        0xa867df55UL,
        0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL,
        0x5268e236UL,
        0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
        0xb2bd0b28UL,
        0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL,
        0x5bdeae1dUL,
        0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL,
        0xeb0e363fUL,
        0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL,
        0x0cb61b38UL,
        0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL,
        0xf1d4e242UL,
        0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
        0x18b74777UL,
        0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL,
        0xf862ae69UL,
        0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL,
        0x3903b3c2UL,
        0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL,
        0xd9d65adcUL,
        0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL,
        0x30b5ffe9UL,
        0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
        0xcdd70693UL,
        0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL,
        0x2a6f2b94UL,
        0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL
    };

    /// @brief 消息头
    struct AsciiHeader
    {
        char Sync;                  // 同步字符，固定为'#'（1字节）
        std::string Message;        // 消息名称（如"GGA"、"BESTNAVA"，最长15字符+1终止符，16字节）
        uint8_t CPUIDle;            // CPU空闲百分比（0-100，1字节）
        std::string TimeRef;        // 时间系统（"GPST"/"BDST"/"GLOST"/"GALST"，8字节）
        std::string TimeStatus;     // 时间质量（"Unknown"/"Fine"，8字节）
        uint16_t gpsWeek;           // GPS周数（2字节）
        uint32_t gpsMs;             // GPS周内秒（毫秒级，4字节）
        uint32_t reserved4;         // 保留字段（4字节）
        uint8_t version;            // Unicore格式版本（1字节）
        int8_t LeapSec;             // 闰秒（-128~127，1字节）
        uint16_t OutputDelay;       // 数据输出延迟（毫秒，2字节）

        // 初始化函数
        AsciiHeader() 
        {
            Sync = '#';
            CPUIDle = 0;
            gpsWeek = 0;
            gpsMs = 0;
            reserved4 = 0;
            version = 0;
            LeapSec = 0;
            OutputDelay = 0;
        }
    };

    /// @brief 从天线 计算的 卫星定位信息
    struct GGAData 
    {
        std::string header;         // 消息头
        std::string utc;            // UTC时间（格式：hhmmss.ss，12字节）
        double lat;                 // 纬度（度，范围：-90~90，保留11位小数）
        char latDir;                // 纬度方向（'N'=北纬/'S'=南纬，1字节）
        double lon;                 // 经度（度，范围：-180~180，保留11位小数）
        char lonDir;                // 经度方向（'E'=东经/'W'=西经，1字节）
        uint8_t qual;               // 定位质量（0=无效,1=单点,2=DGPS,4=RTK固定,5=RTK浮点，1字节）
        uint8_t satCount;           // 参与定位的卫星数（0~99，1字节）
        float hdop;                 // 水平精度因子（0.1~99.9，1字节）
        float alt;                  // 海拔高（米，参考大地水准面，保留4位小数）
        char altUnit;               // 海拔高单位（固定'M'，1字节）
        float undulation;           // 大地水准面差距（米，正=大地水准面高于椭球面，保留4位小数）
        char undulationUnit;        // 大地水准面差距单位（固定'M'，1字节）
        float diffAge;              // 差分数据龄期（秒，非差分定位为空，保留2位小数）
        uint16_t stnID;             // 差分基站ID（0~1023，非差分定位为空，2字节））

        // 初始化函数
        GGAData() 
        {
            lat = 0.0;
            latDir = ' ';
            lon = 0.0;
            lonDir = ' ';
            qual = 0;
            satCount = 0;
            hdop = 0.0f;
            alt = 0.0f;
            altUnit = 'M';
            undulation = 0.0f;
            undulationUnit = 'M';
            diffAge = 0.0f;
            stnID = 0;
        }
    };

    /// @brief 从天线 的 卫星定位信息
    struct RMCData 
    {
        std::string header;         // 消息头
        std::string utc;            // UTC时间（格式：hhmmss.ss，12字节）
        char posStatus;             // 位置状态（'A'=有效/'V'=无效/'D'=差分，1字节）
        double lat;                 // 纬度（度，范围：-90~90，保留11位小数）
        char latDir;                // 纬度方向（'N'=北纬/'S'=南纬，1字节）
        double lon;                 // 经度（度，范围：-180~180，保留11位小数）
        char lonDir;                // 经度方向（'E'=东经/'W'=西经，1字节）
        float speedKn;              // 地面速率（节，保留2位小数）
        float trackTrue;            // 地面航向（度，从真北顺时针，保留2位小数）
        char date[8];               // 日期（格式：ddmmyy，8字节）
        float magVar;               // 磁偏角（度，保留2位小数）
        char varDir;                // 磁偏角方向（'E'=东/'W'=西，1字节）
        char mode;                  // 模式（'A'=自主/'D'=差分/'E'=惯导/'F'=RTK浮点，1字节）
        char navStatus;             // 导航状态（'S'=安全/'C'=注意/'U'=危险/'V'=无效，1字节）

        // 初始化函数
        RMCData() 
        {
            posStatus = 'V';
            lat = 0.0;
            latDir = ' ';
            lon = 0.0;
            lonDir = ' ';
            speedKn = 0.0f;
            trackTrue = 0.0f;
            memset(date, 0, sizeof(date));
            magVar = 0.0f;
            varDir = ' ';
            mode = ' ';
            navStatus = 'V';
        }
    };

    /// @brief 姿态参数
    struct HPRData
    {
        std::string header;         // 消息头
        std::string utc;            // UTC时间（格式：hhmmss.ss，12字节）
        double heading;             // 航向角，0~360 deg
        double pitch;               // 俯仰角，-90~90 deg
        double roll;                // 翻滚角，-90~90 deg
        uint8_t QF;                 // 解状态，具体查看表7-13
        uint16_t satNo;              // 卫星号
        float diffAge;              // 差分数据龄期（秒，非差分定位为空，保留2位小数）
        uint16_t stnID;            // 差分基站ID（0~1023，非差分定位为空，2字节））

        HPRData()
        {
            heading = 0.;
            pitch = 0.;
            roll = 0.;
            QF = 0;
            satNo = 0;
            diffAge = 0.f;
            stnID = 0;
        }
    };

    /// @brief 接收机最佳位置、速度及定向信息
    struct PVTSLNData {
        AsciiHeader asciiHeader;      // ASCII消息头（ASCII格式使用）
        std::string bestPosType;      // 最佳位置类型（参考PosVelType枚举）
        float bestPosHgt;             // 最佳位置海拔高（米，保留4位小数）
        double bestPosLat;            // 最佳位置纬度（度，保留11位小数）
        double bestPosLon;            // 最佳位置经度（度，保留11位小数）
        float bestPosHgtStd;          // 高程标准差（米，保留4位小数）
        float bestPosLatStd;          // 纬度标准差（米，保留4位小数）
        float bestPosLonStd;          // 经度标准差（米，保留4位小数）
        float bestPosDiffAge;         // 最佳位置差分龄期（秒，保留2位小数）
        std::string psrPosType;       // 伪距位置类型（参考PosVelType枚举）
        float psrPosHgt;              // 伪距位置海拔高（米，保留4位小数）
        double psrPosLat;             // 伪距位置纬度（度，保留11位小数）
        double psrPosLon;             // 伪距位置经度（度，保留11位小数）
        float undulation;             // 大地水准面差距（米，保留4位小数）
        uint8_t bestPosSvCount;       // 最佳位置跟踪卫星数（0~99，1字节）
        uint8_t bestPosSolSvCount;    // 最佳位置参与解算卫星数（0~99，1字节）
        uint8_t psrPosSvCount;        // 伪距位置跟踪卫星数（0~99，1字节）
        uint8_t psrPosSolSvCount;     // 伪距位置参与解算卫星数（0~99，1字节）
        double psrVelNorth;           // 伪距速度-北向（米/秒，保留6位小数）
        double psrVelEast;            // 伪距速度-东向（米/秒，保留6位小数）
        double psrVelGround;          // 伪距速度-对地水平（米/秒，保留6位小数）
        std::string headingSolStatus; // 航向解状态（参考SolStatus枚举）
        float headingLength;          // 基线长度（米，0~3000，保留4位小数）
        float headingDegree;          // 航向角（度，0~360，保留4位小数）
        float headingPitch;           // 俯仰角（度，-90~90，保留4位小数）
        uint8_t headingTrackSvCount;  // 航向解主天线跟踪卫星数（0~99，1字节）
        uint8_t headingSolSvCount;    // 航向解参与解算卫星数（0~99，1字节）
        uint8_t headingL1SvCount;     // 航向解L1频点参与卫星数（0~99，1字节）
        uint8_t headingL1L2SvCount;   // 航向解L1+L2频点参与卫星数（0~99，1字节）
        float gdop;                   // 几何精度因子（0.1~99.9，保留2位小数）
        float pdop;                   // 位置精度因子（0.1~99.9，保留2位小数）
        float hdop;                   // 水平精度因子（0.1~99.9，保留2位小数）
        float htdop;                  // 水平+时间精度因子（0.1~99.9，保留2位小数）
        float tdop;                   // 时间精度因子（0.1~99.9，保留2位小数）
        float cutoffAngle;            // 截止高度角（度，0~90，保留1位小数）
        uint16_t prnCount;            // 跟踪卫星PRN总数（0~41，2字节）
        uint16_t prnList[41];         // 跟踪卫星PRN列表（GPS:1-32,BDS:1-64等，2*41字节）

        // 初始化函数
        PVTSLNData()
        {
            asciiHeader.Message = "PVTSLNA";
            bestPosHgt = 0.0f;
            bestPosLat = 0.0;
            bestPosLon = 0.0;
            bestPosHgtStd = 0.0f;
            bestPosLatStd = 0.0f;
            bestPosLonStd = 0.0f;
            bestPosDiffAge = 0.0f;
            psrPosHgt = 0.0f;
            psrPosLat = 0.0;
            psrPosLon = 0.0;
            undulation = 0.0f;
            bestPosSvCount = 0;
            bestPosSolSvCount = 0;
            psrPosSvCount = 0;
            psrPosSolSvCount = 0;
            psrVelNorth = 0.0;
            psrVelEast = 0.0;
            psrVelGround = 0.0;
            headingLength = 0.0f;
            headingDegree = 0.0f;
            headingPitch = 0.0f;
            headingTrackSvCount = 0;
            headingSolSvCount = 0;
            headingL1SvCount = 0;
            headingL1L2SvCount = 0;
            gdop = 0.0f;
            pdop = 0.0f;
            hdop = 0.0f;
            htdop = 0.0f;
            tdop = 0.0f;
            cutoffAngle = 0.0f;
            prnCount = 0;
            memset(prnList, 0, sizeof(prnList));
        }
    };

    // 扩展解状态（参考表7-46）
    struct ExtSolStatus 
    {
        uint8_t rtkCheck : 1;        // Bit0: RTK校验（0=未校验，1=已校验）
        uint8_t ionoCorr : 3;        // Bit1-3: 电离层改正（0=未知，1=Klobuchar，2=SBAS，3=多频，4=伪距差分）
        uint8_t reserved : 4;        // Bit4-7: 保留
    };

    // GPS/GLONASS/BDS2信号掩码（参考表7-44）
    struct GpsGloBds2Mask 
    {
        uint8_t gpsL1 : 1;           // Bit0: 使用GPS L1
        uint8_t gpsL2 : 1;           // Bit1: 使用GPS L2
        uint8_t gpsL5 : 1;           // Bit2: 使用GPS L5
        uint8_t bds2B3I : 1;         // Bit3: 使用BDS2 B3I
        uint8_t gloL1 : 1;           // Bit4: 使用GLONASS L1
        uint8_t gloL2 : 1;           // Bit5: 使用GLONASS L2
        uint8_t bds2B1I : 1;         // Bit6: 使用BDS2 B1I
        uint8_t bds2B2I : 1;         // Bit7: 使用BDS2 B2I
    };

    // Galileo&BDS3信号掩码（参考表7-45）
    struct GalBds3Mask 
    {
        uint8_t galE1 : 1;           // Bit0: 使用Galileo E1
        uint8_t galE5B : 1;          // Bit1: 使用Galileo E5B
        uint8_t galE5A : 1;          // Bit2: 使用Galileo E5A
        uint8_t reserved1 : 1;       // Bit3: 保留
        uint8_t bds3B1I : 1;         // Bit4: 使用BDS3 B1I
        uint8_t bds3B3I : 1;         // Bit5: 使用BDS3 B3I
        uint8_t bds3B2A : 1;         // Bit6: 使用BDS3 B2A
        uint8_t bds3B1C : 1;         // Bit7: 使用BDS3 B1C
    };

    /// @brief BESTNAVA数据结构体（主天线，ASCII格式，参考表7-43）
    struct BESTNAVAData 
    {
        AsciiHeader header;         // ASCII消息头（必选，msgName="BESTNAVA"）
        std::string pSolStatus;     // 位置解状态（参考SolStatus枚举）
        std::string posType;        // 位置类型（参考PosVelType枚举）
        double lat;                 // 纬度（度，保留11位小数）
        double lon;                 // 经度（度，保留11位小数）
        double hgt;                 // 海拔高（米，保留4位小数）
        float undulation;           // 大地水准面差距（米，保留4位小数）
        std::string datumId;        // 坐标系ID（固定"WGS84"，8字节）
        float latStd;               // 纬度标准差（米，保留4位小数）
        float lonStd;               // 经度标准差（米，保留4位小数）
        float hgtStd;               // 高程标准差（米，保留4位小数）
        std::string stnId;          // 基站ID（默认"0000"，4字节）
        float diffAge;              // 差分龄期（秒，保留2位小数）
        float solAge;               // 解龄期（秒，保留2位小数）
        uint8_t svCount;            // 跟踪卫星数（0~99，1字节）
        uint8_t solSvCount;         // 参与解算卫星数（0~99，1字节）
        uint8_t reserved1;          // 保留（1字节）
        uint8_t reserved2;          // 保留（1字节）
        uint8_t reserved3;          // 保留（1字节）
        ExtSolStatus extSolStatus;  // 扩展解状态（1字节）
        GalBds3Mask galBds3Mask;    // Galileo&BDS3信号掩码（1字节）
        GpsGloBds2Mask gpsGloBds2Mask; // GPS/GLONASS/BDS2信号掩码（1字节）
        std::string vSolStatus;     // 速度解状态（参考SolStatus枚举）
        std::string velType;        // 速度类型（参考PosVelType枚举）
        float latency;              // 速度延迟（秒，保留6位小数）
        float velDiffAge;           // 速度差分龄期（秒，保留2位小数）
        double horSpd;              // 对地水平速度（米/秒，保留6位小数）
        double trkGnd;              // 对地轨迹角（度，保留6位小数）
        double vertSpd;             // 垂直速度（米/秒，保留6位小数）
        float verSpdStd;            // 垂直速度标准差（米/秒，保留4位小数）
        float horSpdStd;            // 水平速度标准差（米/秒，保留4位小数）

        // 初始化函数
        BESTNAVAData() {
            header.Message = "BESTNAVA";
            lat = 0.0;
            lon = 0.0;
            hgt = 0.0;
            undulation = 0.0f;
            datumId = "WGS84";
            latStd = 0.0f;
            lonStd = 0.0f;
            hgtStd = 0.0f;
            stnId = "0000";
            diffAge = 0.0f;
            solAge = 0.0f;
            svCount = 0;
            solSvCount = 0;
            reserved1 = 0;
            reserved2 = 0;
            reserved3 = 0;
            memset(&extSolStatus, 0, sizeof(extSolStatus));
            memset(&galBds3Mask, 0, sizeof(galBds3Mask));
            memset(&gpsGloBds2Mask, 0, sizeof(gpsGloBds2Mask));
            latency = 0.0f;
            velDiffAge = 0.0f;
            horSpd = 0.0;
            trkGnd = 0.0;
            vertSpd = 0.0;
            verSpdStd = 0.0f;
            horSpdStd = 0.0f;
        }
    };

    /// @brief BESTNAVHA数据结构体（从天线，ASCII格式，参考表7-48）
    struct BESTNAVHAData 
    {
        AsciiHeader header;         // ASCII消息头（必选，msgName="BESTNAVHA"）
        std::string pSolStatus;     // 位置解状态（参考SolStatus枚举）
        std::string posType;        // 位置类型（参考PosVelType枚举）
        double lat;                 // 纬度（度，保留11位小数）
        double lon;                 // 经度（度，保留11位小数）
        double hgt;                 // 海拔高（米，保留4位小数）
        float undulation;           // 大地水准面差距（米，保留4位小数）
        std::string datumId;        // 坐标系ID（固定"WGS84"，8字节）
        float latStd;               // 纬度标准差（米，保留4位小数）
        float lonStd;               // 经度标准差（米，保留4位小数）
        float hgtStd;               // 高程标准差（米，保留4位小数）
        std::string stnId;          // 基站ID（默认"0000"，4字节）
        float diffAge;              // 差分龄期（秒，保留2位小数）
        float solAge;               // 解龄期（秒，保留2位小数）
        uint8_t svCount;            // 跟踪卫星数（0~99，1字节）
        uint8_t solSvCount;         // 参与解算卫星数（0~99，1字节）
        uint8_t reserved1;          // 保留（1字节）
        uint8_t reserved2;          // 保留（1字节）
        uint8_t reserved3;          // 保留（1字节）
        ExtSolStatus extSolStatus;  // 扩展解状态（1字节）
        GalBds3Mask galBds3Mask;    // Galileo&BDS3信号掩码（1字节）
        GpsGloBds2Mask gpsGloBds2Mask; // GPS/GLONASS/BDS2信号掩码（1字节）
        std::string vSolStatus;     // 速度解状态（参考SolStatus枚举）
        std::string velType;        // 速度类型（参考PosVelType枚举）
        float latency;              // 速度延迟（秒，保留6位小数）
        float velDiffAge;           // 速度差分龄期（秒，保留2位小数）
        double horSpd;              // 对地水平速度（米/秒，保留6位小数）
        double trkGnd;              // 对地轨迹角（度，保留6位小数）
        double vertSpd;             // 垂直速度（米/秒，保留6位小数）
        float verSpdStd;            // 垂直速度标准差（米/秒，保留4位小数）
        float horSpdStd;            // 水平速度标准差（米/秒，保留4位小数）

        // 初始化函数
        BESTNAVHAData() {
            header.Message = "BESTNAVHA";
            lat = 0.0;
            lon = 0.0;
            hgt = 0.0;
            undulation = 0.0f;
            datumId = "WGS84";
            latStd = 0.0f;
            lonStd = 0.0f;
            hgtStd = 0.0f;
            stnId = "0000";
            diffAge = 0.0f;
            solAge = 0.0f;
            svCount = 0;
            solSvCount = 0;
            reserved1 = 0;
            reserved2 = 0;
            reserved3 = 0;
            memset(&extSolStatus, 0, sizeof(extSolStatus));
            memset(&galBds3Mask, 0, sizeof(galBds3Mask));
            memset(&gpsGloBds2Mask, 0, sizeof(gpsGloBds2Mask));
            latency = 0.0f;
            velDiffAge = 0.0f;
            horSpd = 0.0;
            trkGnd = 0.0;
            vertSpd = 0.0;
            verSpdStd = 0.0f;
            horSpdStd = 0.0f;
        }
    };

    /// @brief CRC32校验
    /// @param buf 
    /// @param len 
    /// @return 
    uint32_t crc32_unicore(const uint8_t *buf, int len)
    {
        uint32_t crc = 0;                 /* Init = 0 */
        for (int i = 0; i < len; ++i)
            crc = crc_table[(crc ^ buf[i]) & 0xFF] ^ (crc >> 8);
        return crc;                       /* XorOut = 0，无需再异或 */
    };

    /// @brief CRC32校验
    /// @param message 
    /// @return 
    bool crc32_check(const std::string &message)
    {
        auto it = message.find('#');
        auto nit = message.find('*');
        auto message_cut = message.substr(it + 1, nit - it - 1);

        if (message_cut.empty() || message_cut.length() == message.length())
        {
            return 0;
        }
        
        auto message_hex = message.substr(nit + 1);

        auto crcHex_des = std::stoul(message_hex, nullptr, 16);
        auto crcHex = crc32_unicore((unsigned char *)message_cut.data(), message_cut.size());
        
        return (crcHex == crcHex_des);
    };
    
    /// @brief 校验和验证
    /// @param message 
    /// @return 
    bool sum_check(const std::string& message) {
        // 查找$和*的位置
        size_t start = message.find('$');
        size_t end = message.find('*');
        
        // 计算校验和（$与*之间的字符）
        uint8_t checksum = 0;
        for (size_t i = start + 1; i < end; ++i) {
            checksum ^= static_cast<uint8_t>(message[i]);
        }
        
        // 解析协议中的校验值（*后面的两位十六进制）
        char checksumStr[3] = {0};
        message.copy(checksumStr, 2, end + 1);
        
        // 转换为十六进制数值
        uint8_t receivedChecksum;
        if (sscanf(checksumStr, "%hhx", &receivedChecksum) != 1) {
            return false; // 校验值格式错误
        }
        
        // 对比结果
        return (checksum == receivedChecksum);
    };

    /// @brief 检查数据校验位
    /// @param message 
    /// @return 
    bool check(const std::string& message)
    {
        if (message[0] == '#')
        {
            return crc32_check(message);
        }
        else
        {
            return sum_check(message);
        }
    };

    /// @brief 将数据拆分为消息
    /// @param data 
    /// @return 可用的消息，剩余数据
    std::tuple<std::vector<std::string>, std::vector<uint8_t>> split_messages(const std::vector<uint8_t> & data)
    {
        std::vector<std::string> messages;
        std::string message;
        bool endLetter = 0;

        for (auto &&letter : data)
        {
            if (letter == '\r')
            {
                endLetter = 1;
            }
            else if (letter == '\n')
            {
                if (endLetter == 1)
                {     
                    messages.push_back(message);
                    message.clear();
                }
                
                endLetter = 0;
            }
            else
            {
                endLetter = 0;
    
                message.push_back(letter);
            }
        }

        return {messages,std::vector<uint8_t>(message.begin (), message.end ())};
    };
    
    /// @brief 将消息拆分为字段
    /// @param data 
    /// @return 
    std::vector<std::string> split_message(const std::string& data)
    {
        std::vector<std::string> message;
        std::string word;

        for (auto &&letter : data)
        {
            if (letter == ',' || letter == ';' || letter == '*')
            {
                message.push_back(word);
                word.clear();
            }
            else
            {
                word.push_back(letter);
            }
            
        }
        
        return message;
    };

    class driver
    {
    public:
        bool printINFO = true;
    private:
        std::vector<uint8_t> mem_data;
        serialib serial;

        std::string device;
        int bauds;

        GGAData gga;
        GGAData ggah;
        RMCData rmc; // 弃用
        HPRData hpr;
        PVTSLNData pvtsln; // 弃用
        BESTNAVAData nav; // 弃用
        BESTNAVHAData navh; // 弃用

        std::vector<std::string> messageID;

        /**
         * @brief 检查字符串A中是否包含连续的字符串B
         * @param A 被检查的字符串
         * @param B 要匹配的连续子字符串
         * @return 若A中存在连续的B则返回true，否则返回false
         */
        bool strMatch(const std::string& A, const std::string& B) {
            // 若B为空字符串，默认认为匹配（或根据需求返回false）
            if (B.empty()) {
                return true; // 或 return false; 取决于业务需求
            }
            
            // 若B的长度大于A，直接返回false
            if (B.length() > A.length()) {
                return false;
            }
            
            // 遍历A中可能的起始位置
            for (size_t i = 0; i <= A.length() - B.length(); ++i) {
                // 检查从i开始的子串是否与B匹配
                bool match = true;
                for (size_t j = 0; j < B.length(); ++j) {
                    if (A[i + j] != B[j]) {
                        match = false;
                        break;
                    }
                }
                if (match) {
                    return true;
                }
            }
            
            return false;
        }

        /// @brief 将字符串转化为数字
        /// @tparam T int, double, float
        /// @param str 
        /// @return 
        template <typename T>
        T str2(const std::string & str)
        {
            // 编译期检查：必须是int、float或double
            static_assert(
                std::is_same<T, int>::value ||
                std::is_same<T, float>::value ||
                std::is_same<T, double>::value,
                "错误: 仅支持int、float、double类型!"
            );

            if (str.empty())
            {
                return std::numeric_limits<T>::quiet_NaN();
            }

            if (std::is_same<T, int>())
            {
                return std::stoi(str);
            }
            else if (std::is_same<T, float>())
            {
                return std::stof(str);
            }
            else // std::is_same<T, double>()
            {
                return std::stod(str);
            }
        }

        /// @brief 处理解析后的消息字段
        /// @param words 
        void unpack(const std::vector<std::string> & words)
        {
            std::string msgId = words[0];
            if (strMatch(msgId, "GGA")) 
            {
                // 解析GGA数据
                GGAData tmp;
                
                tmp.header = words[0].substr(1);
                tmp.utc = words.size() > 1 ? words[1] : "";
                
                // 纬度解析（度分格式转度）
                if (words.size() > 2) {
                    double latDeg = str2<double>(words[2].substr(0, 2)); // 度
                    double latMin = str2<double>(words[2].substr(2));    // 分
                    tmp.lat = latDeg + latMin / 60.0;
                }
                tmp.latDir = words.size() > 3 ? words[3][0] : ' ';
                
                // 经度解析（度分格式转度）
                if (words.size() > 4) {
                    double lonDeg = str2<double>(words[4].substr(0, 3)); // 度
                    double lonMin = str2<double>(words[4].substr(3));    // 分
                    tmp.lon = lonDeg + lonMin / 60.0;
                }
                tmp.lonDir = words.size() > 5 ? words[5][0] : ' ';
                
                tmp.qual = words.size() > 6 ? static_cast<uint8_t>(str2<int>(words[6])) : 0;
                tmp.satCount = words.size() > 7 ? static_cast<uint8_t>(str2<int>(words[7])) : 0;
                tmp.hdop = words.size() > 8 ? str2<float>(words[8]) : 0.0f;
                tmp.alt = words.size() > 9 ? str2<float>(words[9]) : 0.0f;
                tmp.altUnit = words.size() > 10 ? words[10][0] : 'M';
                tmp.undulation = words.size() > 11 ? str2<float>(words[11]) : 0.0f;
                tmp.undulationUnit = words.size() > 12 ? words[12][0] : 'M';
                tmp.diffAge = words.size() > 13 ? str2<float>(words[13]) : 0.0f;
                tmp.stnID = words.size() > 14 ? static_cast<uint16_t>(str2<int>(words[14])) : 0;

                if (strMatch(msgId, "GGAH"))
                {
                    ggah = tmp;
                }
                else
                {
                    gga = tmp;
                }
                
                messageID.push_back(words[0].substr(3));
            }
            else if (strMatch(msgId, "RMC")) 
            {
                // 解析RMC数据
                RMCData tmp;

                tmp.header = words[0].substr(1);
                tmp.utc = words.size() > 1 ? words[1] : "";
                tmp.posStatus = words.size() > 2 ? words[2][0] : 'V';
                
                // 纬度解析（度分格式转度）
                if (words.size() > 3) {
                    double latDeg = str2<double>(words[3].substr(0, 2));
                    double latMin = str2<double>(words[3].substr(2));
                    tmp.lat = latDeg + latMin / 60.0;
                }
                tmp.latDir = words.size() > 4 ? words[4][0] : ' ';
                
                // 经度解析（度分格式转度）
                if (words.size() > 5) {
                    double lonDeg = str2<double>(words[5].substr(0, 3));
                    double lonMin = str2<double>(words[5].substr(3));
                    tmp.lon = lonDeg + lonMin / 60.0;
                }
                tmp.lonDir = words.size() > 6 ? words[6][0] : ' ';
                
                tmp.speedKn = words.size() > 7 ? str2<float>(words[7]) : 0.0f;
                tmp.trackTrue = words.size() > 8 ? str2<float>(words[8]) : 0.0f;
                if (words.size() > 9) {
                    strncpy(tmp.date, words[9].c_str(), sizeof(tmp.date)-1);
                }
                tmp.magVar = words.size() > 10 ? str2<float>(words[10]) : 0.0f;
                tmp.varDir = words.size() > 11 ? words[11][0] : ' ';
                tmp.mode = words.size() > 12 ? words[12][0] : ' ';
                tmp.navStatus = words.size() > 13 ? words[13][0] : 'V';

                rmc = tmp;

                messageID.push_back(words[0].substr(3)); // RMC消息标识
            }
            else if (strMatch(msgId, "HPR"))
            {
                // 解析HPR数据
                HPRData tmp;

                tmp.header = words[0].substr(1);
                tmp.utc = words.size() > 1 ? words[1] : "";

                tmp.heading = words.size() > 2 ? str2<double>(words[2]) : std::numeric_limits<double>::quiet_NaN();
                tmp.pitch = words.size() > 3 ? str2<double>(words[3]) : std::numeric_limits<double>::quiet_NaN();
                tmp.roll = words.size() > 4 ? str2<double>(words[4]) : std::numeric_limits<double>::quiet_NaN();

                tmp.QF = words.size() > 5 ? static_cast<uint8_t>(str2<double>(words[5])) : std::numeric_limits<uint8_t>::quiet_NaN();
                tmp.satNo = words.size() > 6 ? static_cast<uint16_t>(str2<double>(words[6])) : std::numeric_limits<uint16_t>::quiet_NaN();
                tmp.diffAge = words.size() > 7 ? static_cast<float>(str2<double>(words[7])) : std::numeric_limits<float>::quiet_NaN();
                tmp.stnID = words.size() > 8 ? static_cast<float>(str2<double>(words[8])) : std::numeric_limits<float>::quiet_NaN();

                hpr = tmp;

                messageID.push_back(words[0].substr(3)); // PVTSLNA消息标识
            }
            else if (strMatch(msgId, "PVTSLNA")) 
            {
                // 解析PVTSLN数据
                PVTSLNData tmp;

                int idx = 0;
                tmp.asciiHeader.Sync = words[idx][0];
                tmp.asciiHeader.Message = words[idx++].substr(1);
                tmp.asciiHeader.CPUIDle = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.asciiHeader.TimeRef = words[idx++];
                tmp.asciiHeader.TimeStatus = words[idx++];
                tmp.asciiHeader.gpsWeek = static_cast<uint16_t>(str2<int>(words[idx++]));
                tmp.asciiHeader.gpsMs = static_cast<uint32_t>(str2<int>(words[idx++]));
                tmp.asciiHeader.reserved4 = static_cast<uint32_t>(str2<int>(words[idx++]));
                tmp.asciiHeader.version = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.asciiHeader.LeapSec = static_cast<int8_t>(str2<int>(words[idx++]));
                tmp.asciiHeader.OutputDelay = static_cast<uint16_t>(str2<int>(words[idx++]));

                tmp.bestPosType = words[idx++];
                tmp.bestPosHgt = str2<float>(words[idx++]);
                tmp.bestPosLat = str2<double>(words[idx++]);
                tmp.bestPosLon = str2<double>(words[idx++]);
                tmp.bestPosHgtStd = str2<float>(words[idx++]);
                tmp.bestPosLatStd = str2<float>(words[idx++]);
                tmp.bestPosLonStd = str2<float>(words[idx++]);
                tmp.bestPosDiffAge = str2<float>(words[idx++]);
                tmp.psrPosType = words[idx++];
                tmp.psrPosHgt = str2<float>(words[idx++]);
                tmp.psrPosLat = str2<double>(words[idx++]);
                tmp.psrPosLon = str2<double>(words[idx++]);
                tmp.undulation = str2<float>(words[idx++]);
                tmp.bestPosSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.bestPosSolSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.psrPosSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.psrPosSolSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.psrVelNorth = str2<double>(words[idx++]);
                tmp.psrVelEast = str2<double>(words[idx++]);
                tmp.psrVelGround = str2<double>(words[idx++]);
                tmp.headingSolStatus = words[idx++];
                tmp.headingLength = str2<float>(words[idx++]);
                tmp.headingDegree = str2<float>(words[idx++]);
                tmp.headingPitch = str2<float>(words[idx++]);
                tmp.headingTrackSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.headingSolSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.headingL1SvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.headingL1L2SvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.gdop = str2<float>(words[idx++]);
                tmp.pdop = str2<float>(words[idx++]);
                tmp.hdop = str2<float>(words[idx++]);
                tmp.htdop = str2<float>(words[idx++]);
                tmp.tdop = str2<float>(words[idx++]);
                tmp.cutoffAngle = str2<float>(words[idx++]);
                tmp.prnCount = static_cast<uint16_t>(str2<int>(words[idx++]));
                
                // 解析PRN列表
                for (uint16_t i = 0; i < tmp.prnCount && i < 41; ++i) {
                    tmp.prnList[i] = static_cast<uint16_t>(str2<int>(words[idx++]));
                }

                pvtsln = tmp;
                
                messageID.push_back("PVTSLNA"); // PVTSLNA消息标识
            }
            else if (strMatch(msgId, "BESTNAVA")) {
                // 解析BESTNAVA数据
                int idx = 0;

                BESTNAVAData tmp;
                
                tmp.header.Sync = words[idx][0];
                tmp.header.Message = words[idx++].substr(1);
                tmp.header.CPUIDle = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.header.TimeRef = words[idx++];
                tmp.header.TimeStatus = words[idx++];
                tmp.header.gpsWeek = static_cast<uint16_t>(str2<int>(words[idx++]));
                tmp.header.gpsMs = static_cast<uint32_t>(str2<int>(words[idx++]));
                tmp.header.reserved4 = static_cast<uint32_t>(str2<int>(words[idx++]));
                tmp.header.version = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.header.LeapSec = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.header.OutputDelay = static_cast<uint16_t>(str2<int>(words[idx++]));

                tmp.pSolStatus = words[idx++];
                tmp.posType = words[idx++];
                tmp.lat = str2<double>(words[idx++]);
                tmp.lon = str2<double>(words[idx++]);
                tmp.hgt = str2<double>(words[idx++]);
                tmp.undulation = str2<float>(words[idx++]);
                tmp.datumId = words[idx++];
                tmp.latStd = str2<float>(words[idx++]);
                tmp.lonStd = str2<float>(words[idx++]);
                tmp.hgtStd = str2<float>(words[idx++]);
                tmp.stnId = words[idx++];
                tmp.diffAge = str2<float>(words[idx++]);
                tmp.solAge = str2<float>(words[idx++]);
                tmp.svCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.solSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.reserved1 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.reserved2 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.reserved3 = static_cast<uint8_t>(str2<int>(words[idx++]));
                
                // 解析扩展解状态（按位解析）
                uint8_t extSol = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.extSolStatus.rtkCheck = extSol & 0x01;
                tmp.extSolStatus.ionoCorr = (extSol >> 1) & 0x07;
                tmp.extSolStatus.reserved = (extSol >> 4) & 0x0F;
                
                // 解析Galileo&BDS3信号掩码
                uint8_t galBds3 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.galBds3Mask.galE1 = galBds3 & 0x01;
                tmp.galBds3Mask.galE5B = (galBds3 >> 1) & 0x01;
                tmp.galBds3Mask.galE5A = (galBds3 >> 2) & 0x01;
                tmp.galBds3Mask.reserved1 = (galBds3 >> 3) & 0x01;
                tmp.galBds3Mask.bds3B1I = (galBds3 >> 4) & 0x01;
                tmp.galBds3Mask.bds3B3I = (galBds3 >> 5) & 0x01;
                tmp.galBds3Mask.bds3B2A = (galBds3 >> 6) & 0x01;
                tmp.galBds3Mask.bds3B1C = (galBds3 >> 7) & 0x01;
                
                // 解析GPS/GLONASS/BDS2信号掩码
                uint8_t gpsGloBds2 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.gpsGloBds2Mask.gpsL1 = gpsGloBds2 & 0x01;
                tmp.gpsGloBds2Mask.gpsL2 = (gpsGloBds2 >> 1) & 0x01;
                tmp.gpsGloBds2Mask.gpsL5 = (gpsGloBds2 >> 2) & 0x01;
                tmp.gpsGloBds2Mask.bds2B3I = (gpsGloBds2 >> 3) & 0x01;
                tmp.gpsGloBds2Mask.gloL1 = (gpsGloBds2 >> 4) & 0x01;
                tmp.gpsGloBds2Mask.gloL2 = (gpsGloBds2 >> 5) & 0x01;
                tmp.gpsGloBds2Mask.bds2B1I = (gpsGloBds2 >> 6) & 0x01;
                tmp.gpsGloBds2Mask.bds2B2I = (gpsGloBds2 >> 7) & 0x01;
                
                tmp.vSolStatus = words[idx++];
                tmp.velType = words[idx++];
                tmp.latency = str2<float>(words[idx++]);
                tmp.velDiffAge = str2<float>(words[idx++]);
                tmp.horSpd = str2<double>(words[idx++]);
                tmp.trkGnd = str2<double>(words[idx++]);
                tmp.vertSpd = str2<double>(words[idx++]);
                tmp.verSpdStd = str2<float>(words[idx++]);
                tmp.horSpdStd = str2<float>(words[idx++]);
                
                messageID.push_back("BESTNAVA"); // BESTNAVA消息标识
            }
            else if (strMatch(msgId, "BESTNAVHA")) {
                // 解析BESTNAVHA数据
                int idx = 0;

                BESTNAVHAData tmp;
                
                tmp.header.Sync = words[idx][0];
                tmp.header.Message = words[idx++].substr(1);
                tmp.header.CPUIDle = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.header.TimeRef = words[idx++];
                tmp.header.TimeStatus = words[idx++];
                tmp.header.gpsWeek = static_cast<uint16_t>(str2<int>(words[idx++]));
                tmp.header.gpsMs = static_cast<uint32_t>(str2<int>(words[idx++]));
                tmp.header.reserved4 = static_cast<uint32_t>(str2<int>(words[idx++]));
                tmp.header.version = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.header.LeapSec = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.header.OutputDelay = static_cast<uint16_t>(str2<int>(words[idx++]));

                tmp.pSolStatus = words[idx++];
                tmp.posType = words[idx++];
                tmp.lat = str2<double>(words[idx++]);
                tmp.lon = str2<double>(words[idx++]);
                tmp.hgt = str2<double>(words[idx++]);
                tmp.undulation = str2<float>(words[idx++]);
                tmp.datumId = words[idx++];
                tmp.latStd = str2<float>(words[idx++]);
                tmp.lonStd = str2<float>(words[idx++]);
                tmp.hgtStd = str2<float>(words[idx++]);
                tmp.stnId = words[idx++];
                tmp.diffAge = str2<float>(words[idx++]);
                tmp.solAge = str2<float>(words[idx++]);
                tmp.svCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.solSvCount = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.reserved1 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.reserved2 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.reserved3 = static_cast<uint8_t>(str2<int>(words[idx++]));
                
                // 解析扩展解状态（按位解析）
                uint8_t extSol = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.extSolStatus.rtkCheck = extSol & 0x01;
                tmp.extSolStatus.ionoCorr = (extSol >> 1) & 0x07;
                tmp.extSolStatus.reserved = (extSol >> 4) & 0x0F;
                
                // 解析Galileo&BDS3信号掩码
                uint8_t galBds3 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.galBds3Mask.galE1 = galBds3 & 0x01;
                tmp.galBds3Mask.galE5B = (galBds3 >> 1) & 0x01;
                tmp.galBds3Mask.galE5A = (galBds3 >> 2) & 0x01;
                tmp.galBds3Mask.reserved1 = (galBds3 >> 3) & 0x01;
                tmp.galBds3Mask.bds3B1I = (galBds3 >> 4) & 0x01;
                tmp.galBds3Mask.bds3B3I = (galBds3 >> 5) & 0x01;
                tmp.galBds3Mask.bds3B2A = (galBds3 >> 6) & 0x01;
                tmp.galBds3Mask.bds3B1C = (galBds3 >> 7) & 0x01;
                
                // 解析GPS/GLONASS/BDS2信号掩码
                uint8_t gpsGloBds2 = static_cast<uint8_t>(str2<int>(words[idx++]));
                tmp.gpsGloBds2Mask.gpsL1 = gpsGloBds2 & 0x01;
                tmp.gpsGloBds2Mask.gpsL2 = (gpsGloBds2 >> 1) & 0x01;
                tmp.gpsGloBds2Mask.gpsL5 = (gpsGloBds2 >> 2) & 0x01;
                tmp.gpsGloBds2Mask.bds2B3I = (gpsGloBds2 >> 3) & 0x01;
                tmp.gpsGloBds2Mask.gloL1 = (gpsGloBds2 >> 4) & 0x01;
                tmp.gpsGloBds2Mask.gloL2 = (gpsGloBds2 >> 5) & 0x01;
                tmp.gpsGloBds2Mask.bds2B1I = (gpsGloBds2 >> 6) & 0x01;
                tmp.gpsGloBds2Mask.bds2B2I = (gpsGloBds2 >> 7) & 0x01;
                
                tmp.vSolStatus = words[idx++];
                tmp.velType = words[idx++];
                tmp.latency = str2<float>(words[idx++]);
                tmp.velDiffAge = str2<float>(words[idx++]);
                tmp.horSpd = str2<double>(words[idx++]);
                tmp.trkGnd = str2<double>(words[idx++]);
                tmp.vertSpd = str2<double>(words[idx++]);
                tmp.verSpdStd = str2<float>(words[idx++]);
                tmp.horSpdStd = str2<float>(words[idx++]);

                navh = tmp;

                messageID.push_back("BESTNAVHA"); // BESTNAVHA消息标识
            }
        };
    public:
        /// @brief 
        /// @param arg1 device
        /// @param arg2 bauds
        driver(const char * arg1, int arg2)
            :device(arg1), bauds(arg2)
        {
            char status = serial.openDevice(device.data(),bauds);
            if (status != 1)
            {
                throw std::runtime_error("RTK driver error: open device: " + device);
            }
            
            std::cout << "RTK driver online at " << device << std::endl;
        }

        ~driver()
        {
            serial.closeDevice();
        };

        /// @brief 获取RTK数据
        /// @return 返回所获取数据的 Message ID，若为空则没有收到数据
        std::vector<std::string> reciveData()
        {
            messageID.clear();

            std::vector<uint8_t> catData;
            if (mem_data.size() > 0)
            {
                catData.insert(catData.end(),mem_data.begin(),mem_data.end());
                mem_data.clear();
            }
            
            auto length = serial.available();
            if (length >0)
            {
                std::vector<uint8_t> buffer(length);
                if (serial.isDeviceOpen())
                {
                    serial.readBytes(buffer.data(),length);
                }
                else
                {
                    throw std::runtime_error("RTK driver error:  device not open");
                }
        
                catData.insert(catData.end(),buffer.begin(),buffer.end());

            }

            auto [messages, rest] = split_messages(catData);
            mem_data = rest;
    
            for (auto &&message : messages)
            {
                if (printINFO)
                {
                    std::cout << "recive message: \n\t" << message << std::endl;
                }
                
                try
                {
                    bool msgCheck = check(message);

                    if (msgCheck)
                    {
                        auto words = split_message(message);
        
                        unpack(words);

                        if (printINFO)
                        {
                            std::cout << "\n\t message unpack success! \n\t" << std::endl;
                        }
                    }
                    else 
                    {
                        if (printINFO)
                        {
                            std::cout << "\n\t message check faild! \n\t" << std::endl;
                        }
                    }
                }
                catch(const std::exception& e)
                {
                    if (printINFO)
                    {
                        std::cout << "\n\t message unpack faild \n\t" << std::endl;
                    }
                    
                    continue;
                }
            }

            return messageID;
        }

        /// @brief 获取主天线计算的定位信息
        /// @return 
        GGAData getGGA()
        {
            return gga;
        }

        /// @brief 获取从天线计算的定位信息
        /// @return 
        GGAData getGGAH()
        {
            return ggah;
        }

        /// @brief 获取计算的姿态信息
        /// @return 
        HPRData getHPR()
        {
            return hpr;
        }

        driver(const driver &) = delete;
        driver operator = (const driver &) = delete;
    };
} // namespace WTRTK_982_4G
